//-----------------------------------------------------------------------
// <copyright file="Create.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Andy Reeves</author>
// <email>andyr</email>
// <date>2004-03-23</date>
// <summary>Creates a new WebSite.</summary>
//-----------------------------------------------------------------------
namespace Microsoft.Sdc.Tasks.Web.WebSite
{
    using System;
    using System.Globalization;
    using Microsoft.Sdc.Tasks.Configuration.Web;
    using Microsoft.Build.Framework;

    /// <summary>
    /// Create a new web site
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[<Web.WebSite.Create 
    ///     Description="description"
    ///     Path="path"
    ///     MachineName="machineName" 
    ///     AuthFlags="authFlags"
    ///     AppPoolId="appPoolId"
    ///     HostName="hostName"
    ///     Identifier="identifier"
    ///     IPAddress="ipAddress"
    ///     Port="port"
    ///     LogFileDir="logFileDir"
    ///     DirBrowseFlags="dirBrowseFlags"
    ///     DefaultDocs="defaultDocs"
    /// />]]></code>
    /// <para>where:</para>
    /// <para><i>description (Required)</i></para>
    /// <para>Web site description to continue.</para>
    /// <para><i>path (Required)</i></para>
    /// <para>Local path to assign as the web root.</para>
    /// <para><i>ipaddress</i></para>
    /// <para>IP address the new site should listen on.</para>
    /// <para><i>port</i></para>
    /// <para>Port number to listen on.</para>
    /// <para><i>hostName</i></para>
    /// <para>Host header to bind to (only valid for non-SSL sites).</para>
    /// <para><i>identifier</i></para>
    /// <para>Web site identifier to continue.</para>
    /// <para><i>authFlags</i></para>
    /// <para>Authentication flags to apply to the site.</para>
    /// <para><i>logFileDir</i></para>
    /// <para>Local path to assign as the folder that contains the log files.</para>
    /// <para><i>appPoolId</i></para>
    /// <para>Application pool to run the site within (IIS6 only).</para>
    /// <para><i>dirBrowseFlags</i></para>
    /// <para>Directory browsing flags to apply to the site.</para>
    /// <para><i>DefaultDocs</i></para>
    /// <para>Document names allowed as default document for the site.</para>
    /// <para><i>machineName</i></para>
    /// <para>Machine to operate on(defaults to localhost)</para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <Web.WebSite.Create 
    ///             Description='My New Site'
    ///             Path='$(CurrentFolder)\Solution\Secure'/>
    ///     </Target>
    ///     <Target Name="TestWithDefaultDoc" >
    ///         <Web.WebSite.Create 
    ///             Description='My New Site'
    ///             Path='$(CurrentFolder)\Solution\Secure'
    ///             DirBrowseFlags="EnableDefaultDoc"
    ///             DefaultDocs="Default.aspx;Default.html;index.html;index.htm" />
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>    
    public class Create : TaskBase
    {
        private string description;
        private string path;
        private string ipAddress;
        private string port = "80";
        private string hostName;
        private string identifier;
        private string authFlagsFromConfig;
        private string appPoolId;
        private string anonymousUserName;
        private string anonymousPassword;
        private string httpExpires;
        private string logFileDir;
        private string dirBrowseFlagsFromConfig;
        private DirBrowseFlags dirBrowseFlags;
        private ITaskItem[] defaultDocs;
        private AuthFlags authFlags = 0;
        private Microsoft.Sdc.Tasks.Configuration.Web.WebSite web;
        private bool force;
        private string machineName = "localhost";

        /// <summary>
        /// Machine to operate on
        /// </summary>
        public string MachineName
        {
            get { return this.machineName; }
            set { this.machineName = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to Delete a website if it exists.
        /// </summary>
        /// <value><c>true</c> if force; otherwise, <c>false</c>.</value>
        public bool Force
        {
            get { return this.force; }
            set { this.force = value; }
        }

        /// <summary>
        /// Gets or sets the Description of web site to apply binding to
        /// </summary>
        /// <value>A valid web site description</value>
        [Required]
        public string Description
        {
            get { return (this.description ?? String.Empty); }
            set { this.description = value; }
        }

        /// <summary>
        /// Gets or sets the Root path for the web site
        /// </summary>
        /// <value>Existing directory path</value>
        [Required]
        public string Path
        {
            get { return (this.path ?? String.Empty); }
            set { this.path = value; }
        }

        /// <summary>
        /// Gets or sets the IP address to bind web site.
        /// </summary>
        /// <value>A value IP address</value>
        /// <remarks>If this property is not specified the web site will listen on all 
        /// available IP addresses</remarks>
        public string IPAddress
        {
            get { return (this.ipAddress ?? String.Empty); }
            set { this.ipAddress = value; }
        }

        /// <summary>
        /// Gets or sets the Port number to listen on
        /// </summary>
        /// <value>A value port number</value>
        public string Port
        {
            get { return (this.port ?? String.Empty); }
            set { this.port = value; }
        }

        /// <summary>
        /// Gets or sets the IP address to bind web site.
        /// </summary>
        /// <value>A value IP address</value>
        /// <remarks>If this property is not specified the web site will listen on all 
        /// available IP addresses</remarks> 
        public string HostName
        {
            get { return (this.hostName ?? String.Empty); }
            set { this.hostName = value; }
        }

        /// <summary>
        /// Gets or sets the Web site identifier
        /// </summary>
        /// <value>Any non-existant web site identifier</value>
        /// <remarks>If this property is not defined a web site identifier will be generated 
        /// on site creation.</remarks>
        [Output]
        public string Identifier
        {
            get { return (this.identifier ?? String.Empty); }
            set { this.identifier = value; }
        }

        /// <summary>
        /// Gets or sets the Authentication methods for the site
        /// </summary>
        /// <value>A combination of </value>
        /// <value>NTLM </value>
        /// <value>Anonymous </value>
        /// <value>Basic </value>
        /// <value>Digest</value>
        /// <remarks>If unspecified the site will default to anonymous and NTLM</remarks>
        public string AuthFlags
        {
            get { return (this.authFlagsFromConfig ?? String.Empty); }
            set { this.authFlagsFromConfig = value; }
        }

        /// <summary>
        /// Gets or sets the Application Pool Identifier
        /// </summary>
        /// <value>Application pool to run the web site under</value>
        /// <remarks>IIS6 and above only</remarks>
        public string AppPoolId
        {
            get { return (this.appPoolId ?? "DefaultAppPool"); }
            set { this.appPoolId = value; }
        }

        /// <summary>
        /// Gets or sets the anonymous username.
        /// </summary>
        /// <value>The anonymous username.</value>
        public string AnonymousUsername
        {
            get { return (this.anonymousUserName ?? String.Empty); }
            set { this.anonymousUserName = value; }
        }

        /// <summary>
        /// Gets or sets the anonymous password.
        /// </summary>
        /// <value>The anonymous password.</value>
        public string AnonymousPassword
        {
            get { return (this.anonymousPassword ?? String.Empty); }
            set { this.anonymousPassword = value; }
        }

        /// <summary>
        /// Gets or sets the Number of hours after which the content needs to be expired
        /// </summary>
        public string HttpExpires
        {
            get { return (this.httpExpires ?? String.Empty); }
            set { this.httpExpires = value; }
        }

        /// <summary>
        /// Gets or sets the Path to log folder
        /// </summary>
        public string LogFileDir
        {
            get { return (this.logFileDir ?? String.Empty); }
            set { this.logFileDir = value; }
        }

        /// <summary>
        /// Gets or sets the Directory browsing settings for this site.  Use None alone to clear all flags.
        /// </summary>
        /// <value>A combination of</value>
        /// <value>None</value>
        /// <value>ShowDate</value>
        /// <value>ShowExtension</value>
        /// <value>ShowLongDate</value>
        /// <value>ShowSize</value>
        /// <value>ShowTime</value>
        /// <value>EnableDefaultDoc</value>
        /// <value>EnableDirBrowsing</value>
        public string DirBrowseFlags
        {
            get { return (String.IsNullOrEmpty(this.dirBrowseFlagsFromConfig) ? String.Empty : this.dirBrowseFlagsFromConfig); }
            set { this.dirBrowseFlagsFromConfig = value; }
        }

        /// <summary>
        /// Gets or sets the Default documents list.  DirBrowseFlags must have EnableDefaultDoc for this list to be in effect.
        /// </summary>
        /// <value>Semicolon-delimited list of default document names in order of precedence.</value>
        public ITaskItem[] DefaultDocs
        {
            get { return this.defaultDocs; }
            set { this.defaultDocs = value; }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            #region Execute code

            if (string.IsNullOrEmpty(this.authFlagsFromConfig))
            {
                this.authFlags = Microsoft.Sdc.Tasks.Configuration.Web.AuthFlags.Anonymous | Microsoft.Sdc.Tasks.Configuration.Web.AuthFlags.NTLM;
            }
            else
            {
                string[] authFlagsSplit = this.authFlagsFromConfig.Split(' ');
                foreach (string authFlagsSplitItem in authFlagsSplit)
                {
                    object flags = Enum.Parse(typeof(AuthFlags), authFlagsSplitItem, true);
                    this.authFlags = this.authFlags | (AuthFlags) flags;
                }
            }

            if (Microsoft.Sdc.Tasks.Configuration.Web.WebSite.Exists(this.MachineName, this.Description) && this.Force == false)
            {
                Log.LogMessage(string.Format("Website: {0} already exists on: {1}", this.Description, this.MachineName));
                return;
            }

            if (Microsoft.Sdc.Tasks.Configuration.Web.WebSite.Exists(this.MachineName, this.Description) && this.Force)
            {
                Log.LogMessage(string.Format("Website: {0} already exists on: {1}, Deleting website as Force is true", this.Description, this.MachineName));
                WebSite.Delete(this.Description, this.MachineName);
            }

            if (string.IsNullOrEmpty(this.Path))
            {
                Log.LogError("Path not specified.");
                return;
            }

            if (string.IsNullOrEmpty(this.Description))
            {
                Log.LogError("Description not specified.");
                return;
            }

            Log.LogMessage(string.Format("Creating website: {0} on: {1}", this.Description, this.MachineName));
            this.web = new Microsoft.Sdc.Tasks.Configuration.Web.WebSite(this.MachineName);
            this.web.Description = this.description;
            this.web.Path = System.IO.Path.GetFullPath(this.path);
            this.web.Port = Convert.ToInt32(this.port, CultureInfo.InvariantCulture);
            this.web.RootAuthFlags = this.authFlags;
            this.web.AppPoolId = this.AppPoolId;
            this.web.LogFileDirectory = this.logFileDir;

            if (string.IsNullOrEmpty(this.HostName) == false)
            {
                this.web.HostName = this.HostName;
            }

            if (string.IsNullOrEmpty(this.AnonymousUsername) == false)
            {
                this.web.AnonymousUserName = this.AnonymousUsername;
            }

            if (string.IsNullOrEmpty(this.AnonymousPassword) == false)
            {
                this.web.AnonymousPassword = this.AnonymousPassword;
            }

            if (string.IsNullOrEmpty(this.IPAddress) == false)
            {
                this.web.IPAddress = System.Net.IPAddress.Parse(this.ipAddress);
            }

            if (string.IsNullOrEmpty(this.Identifier) == false)
            {
                this.web.Identifier = Convert.ToInt32(this.identifier, CultureInfo.InvariantCulture);
            }

            if (string.IsNullOrEmpty(this.HttpExpires) == false)
            {
                this.web.HttpExpires = this.HttpExpires;
            }

            if (string.IsNullOrEmpty(this.DirBrowseFlags) == false)
            {
                string[] dirBrowseFlagsSplit = this.dirBrowseFlagsFromConfig.Split(' ');
                foreach (string dirBrowseFlagsSplitItem in dirBrowseFlagsSplit)
                {
                    object flags = Enum.Parse(typeof(DirBrowseFlags), dirBrowseFlagsSplitItem, true);
                    this.dirBrowseFlags = this.dirBrowseFlags | (DirBrowseFlags) flags;
                }

                this.web.DirBrowseFlags = this.dirBrowseFlags;
            }
            else
            {
                this.web.DirBrowseFlags = null;
            }

            if (this.DefaultDocs != null && this.DefaultDocs.Length > 0)
            {
                string[] sDefaultDocs = Array.ConvertAll<ITaskItem, string>(this.DefaultDocs, new Converter<ITaskItem, string>(delegate(ITaskItem item) { return item.ItemSpec; }));
                this.web.DefaultDocs = string.Join(", ", sDefaultDocs);
            }

            this.web.Save();
            this.identifier = this.web.Identifier.ToString();

            #endregion
        }
    }
}